{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a name=\"top\"></a><img src=\"source/SpinalHDL.png\" alt=\"SpinalHDL based on Scala\" style=\"width:320px;\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Before running Spinal HDL code, be sure to load SpinalHDL Libraries  \n",
    "**Note** : This may be a little slow when the first time load, please wait a moment to download Lib from remote.)   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val path = System.getProperty(\"user.dir\") + \"/source/load-spinal.sc\"\n",
    "interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. val def in Trait\n",
    "**Attation** val cause Error "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait PRNBase {\n",
    "  val size: Int \n",
    "\n",
    "  val Mask = (1 << size) - 1\n",
    "  val Msb  = (1 << (size - 1))\n",
    "}\n",
    "\n",
    "object GPS extends PRNBase{\n",
    "    val size = 1023\n",
    "}\n",
    "\n",
    "object BD extends PRNBase{\n",
    "    val size = 2046\n",
    "}\n",
    "BD.Mask toHexString // return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait PRNBase {\n",
    "  val size: Int \n",
    "\n",
    "  def Mask = (1 << size) - 1\n",
    "  def Msb  = (1 << (size - 1))\n",
    "}\n",
    "object BD extends PRNBase{\n",
    "    val size = 11\n",
    "}\n",
    "BD.Mask toHexString"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Scala double definition  \n",
    "```scala \n",
    "class TestDoubleDef{\n",
    "  def foo(p:List[String]) = {}\n",
    "  def foo(p:List[Int]) = {}\n",
    "}\n",
    "```\n",
    "**raise Error:**\n",
    "```sh\n",
    "[error] double definition:\n",
    "[error] method foo:(List[String])Unit and\n",
    "[error] method foo:(List[Int])Unit at line 120\n",
    "[error] have same type after erasure: (List)Unit \n",
    "```\n",
    "Solution: https://stackoverflow.com/questions/3307427/scala-double-definition-2-methods-have-the-same-type-erasure/3544060#3544060"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "object MyTransform{\n",
    "  def apply(x: Int ): Double              = x + 0.00 \n",
    "  def apply(x: List[Int] ): List[Double]  = x.map(_+0.00)\n",
    "  def apply(x: List[Double] ): List[Double] = x.map(_+0.00)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Use implict transform**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "case class IntList(list: List[Int])\n",
    "case class LongList(list: List[Double])\n",
    "case class DoubleList(list: List[Double])\n",
    "\n",
    "implicit def Il(list: List[Int]) = IntList(list)\n",
    "implicit def Ll(list: List[Double]) = LongList(list)\n",
    "implicit def Dl(list: List[Double]) = DoubleList(list)\n",
    "\n",
    "object FixTo{\n",
    "  def apply(x: Int ): Double              = x + 0.00 \n",
    "  def apply(x: IntList ): List[Double]    = x.list.map(_+0.00)\n",
    "  def apply(x: LongList ): List[Double]   = x.list.map(_+0.00)\n",
    "  def apply(x: DoubleList ): List[Double] = x.list.map(_+0.00)\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val a = FixTo(3)\n",
    "val b = FixTo(DoubleList(List(1,2,3,4,5)))\n",
    "val c = FixTo(List(1,2,3,4,5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    " "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Timethis  \n",
    "```scala \n",
    " val beg = System.currentTimeMillis()\n",
    " ... block \n",
    " val gap = System.currentTimeMillis() - beg\n",
    " println(s\"time consume $gap ms\")\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    " val beg = System.currentTimeMillis()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Peformance  \n",
    "```scala \n",
    " val data = List.fill(100000)(rand.nextInt)\n",
    " val sum = data.foldLeft(0)(_+_)\n",
    " val content = data.map(_.toString).foldLeft(\"\")(_+_)  // Attation!! bad-performance\n",
    " val content = data.mkString(\"\\n\")                     // this is recommended\n",
    " import java.io.PrintWriter\n",
    " new PrintWriter(\"./test.txt\"){write(content);close} \n",
    "```\n",
    "\n",
    "So it's better not to use foldLeft/foldRight for string splicing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Sequence slicing\n",
    "- Way1: `map(i => source(i * step))` **×**\n",
    "- Way2: `source.sliding(step, step).map(_.head).toList`  **√**\n",
    "- Way3: `map(i => source(i * step))` **×**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Way1 `15s`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val rand = new scala.util.Random(0)\n",
    "val source = List.fill(16384*16)(rand.nextDouble())\n",
    "val step = 8\n",
    "SpinalProgress(\"start\")\n",
    "//val x = (0 until source.size/step).map(i => source(i*step))\n",
    "SpinalProgress(\"done\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Way2  `0.03S` recomonded\n",
    "equal\n",
    "```scala \n",
    "val x = source.grouped(step).map(_.head).toList\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SpinalProgress(\"start\")\n",
    "val x = source.sliding(step, step).map(_.head).toList\n",
    "SpinalProgress(\"done\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Way3 `45s`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SpinalProgress(\"start\")\n",
    "val x = for(i <- 0 until source.size/step) yield source(i*downTimes)\n",
    "SpinalProgress(\"done\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Scala",
   "language": "scala",
   "name": "scala"
  },
  "language_info": {
   "codemirror_mode": "text/x-scala",
   "file_extension": ".scala",
   "mimetype": "text/x-scala",
   "name": "scala",
   "nbconvert_exporter": "script",
   "version": "2.12.8"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
